package com.yeskery.nut.application;

import com.yeskery.nut.bind.*;
import com.yeskery.nut.bind.validator.CustomMethodParamValidatorHandler;
import com.yeskery.nut.core.*;
import com.yeskery.nut.plugin.PluginManager;
import com.yeskery.nut.script.expression.NutExpression;
import com.yeskery.nut.script.function.Function;
import com.yeskery.nut.script.function.FunctionContext;
import com.yeskery.nut.util.StringUtils;
import com.yeskery.nut.view.WebViewConfigure;

import java.util.*;

/**
 * Nut Web 相关配置接口实现类
 * @author sprout
 * @version 1.0
 * 2022-06-12 18:20
 */
public class NutConfigureImpl implements NutConfigure {

    /** 扫描的基础包 */
    private final Set<String> basePackages = new HashSet<>();

    /** 自定义方法参数处理器map */
    private final Map<Class<?>, CustomMethodParamBindHandler<?>> customMethodParamHandlerMap = new HashMap<>();

    /** 自定义参数验证处理器集合 */
    private final Set<CustomMethodParamValidatorHandler> customMethodParamValidatorHandlers = new HashSet<>();

    /** 响应体处理器集合 */
    private final Set<ResponseBodyHandler> responseBodyHandlers = new HashSet<>();

    /** Http响应体处理器集合 */
    private final Set<HttpResponseBodyHandler> httpResponseBodyHandlers = new HashSet<>();

    /** 要忽略的自动探测类集合 */
    private final Set<Class<? extends AutoDetector>> ignoreAutoDetectorClasses = new HashSet<>();

    /** 自动探测类集合 */
    private final List<AutoDetector> autoDetectors = new LinkedList<>();

    /** 命令行执行函数集合 */
    private final List<CommandLineRunner> commandLineRunners = new LinkedList<>();

    /** 程序执行函数集合 */
    private final List<ApplicationRunner> applicationRunners = new LinkedList<>();

    /** 自定义函数集合 */
    private final List<Function> customFunctionList = new LinkedList<>();

    /** 自定义视图表达式集合 */
    private final List<NutExpression> customNutExpressionList = new LinkedList<>();

    /** 安全的服务上下文 */
    private SecureServerContext secureServerContext;

    /** 环境对象 */
    private Environment environment;

    /** 请求转发器 */
    private Dispatcher dispatcher;

    /** 视图配置对象 */
    private WebViewConfigure webViewConfigure;

    /** 服务上下文 */
    private ServerContext serverContext;

    /** Controller 控制器 */
    private ControllerManager controllerManager;

    /** Session 管理器 */
    private SessionManager sessionManager;

    /** 插件管理器 */
    private PluginManager pluginManager;

    /** 函数上下文 */
    private FunctionContext functionContext;

    @Override
    public SecureServerContext setSecureServerContext(SecureServerContext secureServerContext) {
        return this.secureServerContext = secureServerContext;
    }

    @Override
    public SecureServerContext getSecureServerContext() {
        return secureServerContext;
    }

    @Override
    public Dispatcher getDispatcher() {
        return dispatcher;
    }

    @Override
    public WebViewConfigure getWebViewConfigure() {
        return webViewConfigure;
    }

    @Override
    public ServerContext getServerContext() {
        return serverContext;
    }

    @Override
    public ControllerManager getControllerManager() {
        return controllerManager;
    }

    @Override
    public SessionManager getSessionManager() {
        return sessionManager;
    }

    @Override
    public PluginManager getPluginManager() {
        return pluginManager;
    }

    @Override
    public FunctionContext getFunctionContext() {
        return functionContext;
    }

    @Override
    public void registerCustomScriptExpression(NutExpression expression) {
        customNutExpressionList.add(expression);
    }

    @Override
    public void addBasePackage(String basePackage) {
        if (basePackages.stream().noneMatch(basePackage::startsWith)) {
            basePackages.add(basePackage);
        }
    }

    @Override
    public void addBasePackage(Class<?> mainClass) {
        if (mainClass.getPackage() != null) {
            basePackages.add(mainClass.getPackage().getName());
        }
    }

    @Override
    public Set<String> getBasePackages() {
        return basePackages;
    }

    @Override
    public <T> void addMethodParamBindHandler(CustomMethodParamBindHandler<T> bindHandler) {
        Class<T> clazz = bindHandler.getHandleType();
        if (FitValueHelper.getInstance().isBasicTypeClass(clazz)) {
            throw new DataBindException("Can't Bind Basic Type [" + clazz +  "] For BindHandler.");
        }
        customMethodParamHandlerMap.put(clazz, bindHandler);
    }

    @Override
    public Map<Class<?>, CustomMethodParamBindHandler<?>> getMethodParamBindHandlers() {
        return customMethodParamHandlerMap;
    }

    @Override
    public void addMethodParamValidatorHandler(CustomMethodParamValidatorHandler validatorHandler) {
        customMethodParamValidatorHandlers.add(validatorHandler);
    }

    @Override
    public Set<CustomMethodParamValidatorHandler> getMethodParamValidatorHandlers() {
        return customMethodParamValidatorHandlers;
    }

    @Override
    public void addResponseBodyHandler(ResponseBodyHandler responseBodyHandler) {
        responseBodyHandlers.add(responseBodyHandler);
    }

    @Override
    public Set<ResponseBodyHandler> getResponseBodyHandlers() {
        return responseBodyHandlers;
    }

    @Override
    public void addHttpResponseBodyHandler(HttpResponseBodyHandler httpResponseBodyHandler) {
        httpResponseBodyHandlers.add(httpResponseBodyHandler);
    }

    @Override
    public Set<HttpResponseBodyHandler> getHttpResponseBodyHandlers() {
        return httpResponseBodyHandlers;
    }

    @Override
    public void addIgnoreAutoDetectClass(Class<? extends AutoDetector> autoDetectorClass) {
        ignoreAutoDetectorClasses.add(autoDetectorClass);
    }

    @Override
    public void registerAutoDetector(AutoDetector autoDetector) {
        autoDetectors.add(autoDetector);
    }

    @Override
    public void setEnvironment(Environment environment) {
        if (environment == null) {
            environment = new DefaultEnvironment();
        }
        this.environment = environment;
    }

    @Override
    public void setEnvironment(String environment) {
        if (StringUtils.isEmpty(environment)) {
            setEnvironment(new DefaultEnvironment());
        } else {
            setEnvironment(new DefaultEnvironment(environment));
        }
    }

    @Override
    public Environment getEnvironment() {
        if (this.environment == null) {
            this.environment = new DefaultEnvironment(false);
        }
        return this.environment;
    }

    @Override
    public void addRunner(CommandLineRunner runner) {
        if (runner != null && commandLineRunners.stream().map(Object::getClass).noneMatch(c -> c == runner.getClass())) {
            commandLineRunners.add(runner);
        }
    }

    @Override
    public void addRunner(ApplicationRunner runner) {
        if (runner != null && applicationRunners.stream().map(Object::getClass).noneMatch(c -> c == runner.getClass())) {
            applicationRunners.add(runner);
        }
    }

    @Override
    public void registerCustomScriptFunction(Function function) {
        customFunctionList.add(function);
    }

    /**
     * 设置 Nut 的 {@link Dispatcher}
     * @param dispatcher {@link Dispatcher}
     */
    public void setDispatcher(Dispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }

    /**
     * 设置视图配置对象
     * @param webViewConfigure 视图配置对象
     */
    public void setWebViewConfigure(WebViewConfigure webViewConfigure) {
        this.webViewConfigure = webViewConfigure;
    }

    /**
     * 设置 Nut 的 {@link ServerContext}
     * @param serverContext {@link ServerContext}
     */
    public void setServerContext(ServerContext serverContext) {
        this.serverContext = serverContext;
    }

    /**
     * 设置 Nut 的 {@link ControllerManager}
     * @param controllerManager {@link ControllerManager}
     */
    public void setControllerManager(ControllerManager controllerManager) {
        this.controllerManager = controllerManager;
    }

    /**
     * 设置 Nut 的 {@link SessionManager}
     * @param sessionManager {@link SessionManager}
     */
    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    /**
     * 设置 Nut 的 {@link PluginManager}
     * @param pluginManager {@link PluginManager}
     */
    public void setPluginManager(PluginManager pluginManager) {
        this.pluginManager = pluginManager;
    }

    /**
     * 设置 Nut 的 {@link FunctionContext}
     * @param functionContext {@link FunctionContext}
     */
    public void setFunctionContext(FunctionContext functionContext) {
        this.functionContext = functionContext;
    }

    /**
     * 获取要忽略的自动探测类集合
     * @return 要忽略的自动探测类集合
     */
    public Set<Class<? extends AutoDetector>> getIgnoreAutoDetectorClasses() {
        return ignoreAutoDetectorClasses;
    }

    /**
     * 获取自动探测器集合
     * @return 自动探测器集合
     */
    public List<AutoDetector> getAutoDetectors() {
        return autoDetectors;
    }

    /**
     * 获取命令行执行函数
     * @return 命令行执行函数
     */
    public List<CommandLineRunner> getCommandLineRunners() {
        return commandLineRunners;
    }

    /**
     * 获取程序执行函数
     * @return 程序执行函数
     */
    public List<ApplicationRunner> getApplicationRunners() {
        return applicationRunners;
    }

    /**
     * 获取自定义脚本函数集合
     * @return 自定义脚本函数集合
     */
    public List<Function> getCustomScriptFunctions() {
        return customFunctionList;
    }

    /**
     * 获取自定义视图表达式集合
     * @return 自定义视图表达式集合
     */
    public List<NutExpression> getCustomNutExpressions() {
        return customNutExpressionList;
    }
}
